Adapter中的onCreateViewHolder和onBindViewHolder

在实现Adapter的时候,至少需要重写三个方法:getItemCount、onCreateViewHolder和onBindViewHolder,getItemCount一般是返回数据表的长度,比较简单,但是onCreateViewHolder和onBindViewHolder中遇到的坑比较多。

ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

这个方法中会构造两个东西,一个叫View,很熟悉,另一个叫ViewHolder,虽然不那么熟悉,但是顾名思义ViewHolder就是用来装View的容器。可以把View中的一些控件提取出来放到ViewHolder中存起来,避免每次都findViewById,也可以把一些与View相关的临时变量放在里面,最重要的一点就是ViewHolder与View永久绑定,所以把View对象的引用存在ViewHolder中可以随时从ViewHolder中获取对应的View来操作视图。Javadoc是这样写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Called when RecyclerView needs a new ViewHolder of the given type to represent
an item.

当RecyclerView需要一个对应类型的新的ViewHolder时会调用这个方法。

This new ViewHolder should be constructed with a new View that can represent the
items of the given type. You can either create a new View manually or inflate it
from an XML layout file.

你应当用一个对应类型的view来初始化一个ViewHolder,你可以自己构建这个view,也可以通过XML
布局文件中构建。

The new ViewHolder will be used to display items of the adapter using
onBindViewHolder(ViewHolder, int, List). Since it will be re-used to display
different items in the data set, it is a good idea to cache references to sub
views of the View to avoid unnecessary View.findViewById(int) calls.

这个新的ViewHolder将会在onBindViewHolder中绑定数据并显示在屏幕上。因为它会在更换数据的
时候重复利用,所以在ViewHolder中保存子视图的引用来减少findViewById的调用是个不错的做法。

这里有个坑,这里创建的ViewHolder和与之对应的View永久绑定,但是它们跟数据只是临时绑定!
什么意思呢,绝对不可以把数据放在ViewHolder里面,因为ViewHolder和Data的关系会变。举个例子,ViewHolder相当于抽屉,在抽屉里放东西(Data),一个抽屉里面的东西可以是你有的任何一件,东西的数量可以远大于抽屉数量,因为多的可以不放在抽屉里,但是ViewHolder的数量就那么多,它不会随着东西的增多而变多。

void onBindViewHolder(ViewHolder holder, int position)

这个方法在数据与View-ViewHolder绑定的时候被调用的,看Javadoc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Called by RecyclerView to display the data at the specified position. This method should
update the contents of the ViewHolder.itemView to reflect the item at the given position.

RecyclerView在特定位置显示数据的时候会调用这个方法,这个方法应当根据对应位置的数据来更新ViewHolder
中对应的View视图。

Note that unlike ListView, RecyclerView will not call this method again if the position
of the item changes in the data set unless the item itself is invalidated or the new
position cannot be determined. For this reason, you should only use the position parameter
while acquiring the related data item inside this method and should not keep a copy of it.
If you need the position of an item later on (e.g. in a click listener), use
ViewHolder.getAdapterPosition() which will have the updated adapter position.

注意它将不同于ListView,在完成绑定之后,当对应位置的数据被修改之后,这个方法不会被重新调用,除非
item本身已经失效或者新的位置无法确定。(在数据改变时,开发者应当主动地调用notify*系列方法通知刷新
视图,之后RecyclerView会重新调用这个方法重新绑定视图)。因为这个原因,你应该用position参数从
DataList中获取数据而不能把数据存在ViewHolder里面。如果在之后需要获取position,可以用
ViewHolder.getAdapterPosition()来实时获取当时绑定的数据position。

Override onBindViewHolder(ViewHolder, int, List) instead if Adapter can handle efficient
partial bind.

多种Item类型的应用

待更新…